package com.jackrain.nea.fc.vp.service;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;
import com.aliyun.opensearch.OpenSearchClient;
import com.aliyun.opensearch.SearcherClient;
import com.aliyun.opensearch.sdk.dependencies.com.google.common.collect.Lists;
import com.aliyun.opensearch.sdk.generated.OpenSearch;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchClientException;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchException;
import com.aliyun.opensearch.sdk.generated.search.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.jackrain.nea.config.PropertiesConf;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.fc.utils.Constants;
import com.jackrain.nea.fc.vp.api.CvipSearchCmd;
import com.jackrain.nea.sys.CommandAdapter;
import com.jackrain.nea.util.ApplicationContextHandle;
import com.jackrain.nea.util.RuntimeCompute;
import com.jackrain.nea.util.ValueHolder;
import com.jackrain.nea.web.face.User;
import com.jackrain.nea.web.query.DefaultWebEvent;
import com.jackrain.nea.web.query.QuerySession;
import io.searchbox.client.JestClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.source.FetchSourceContext;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;


@Slf4j
@Component
@Service(protocol = "dubbo", validation = "true", version = "1.0", group = "vp")
public class CvipSearchCmdImpl extends CommandAdapter implements CvipSearchCmd {

    @Autowired
    private PropertiesConf pconf;

    @Autowired
    private JestClient jestClient;

    private Logger accesLogger = LoggerFactory.getLogger(Constants.ACCESS_PARAM_LOGGER);

    @Override
    public ValueHolder execute(QuerySession querySession) throws NDSException {
        RuntimeCompute runtimeCompute = ApplicationContextHandle.getBean("runtimeCompute");
        runtimeCompute.startRuntime();
        ValueHolder valueHolder = new ValueHolder();
        User user = querySession.getUser();
        DefaultWebEvent event = querySession.getEvent();
        JSONObject param = JSON.parseObject(JSON.toJSONStringWithDateFormat(event.getParameterValue("param"), "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteMapNullValue), Feature.OrderedField);
//        log.info("vipsearch-->" + param);
        log.info("CvipSearchCmdImpl--param-->{}",param);

        //获取查询条件字段类型是index还是filter
        JSONArray searchtypes = param.getJSONArray("searchtype");
        //获取查询条件字段
        JSONObject fixedcolumns = param.getJSONObject("fixedcolumns");
        //获取排序字段
        JSONArray orderby = param.getJSONArray("orderby");

        boolean open = true;
        Long maxId = 1L;
        JSONArray storeIds = new JSONArray();
        while (open) {
            ValueHolder opensearch = opensearch(querySession, maxId, storeIds);
            if ("-1".equals(opensearch.get("code"))) {
                if (null != param.getString("issql") && param.getBoolean("issql")) {
                    String ids = "(0)";
                    opensearch.put("IDS", ids);
                } else {
                    JsonArray ids = new JsonArray();
                    opensearch.put("IDS", ids);
                }
                opensearch.put("TOTAL", 0);
                return opensearch;
            }
            maxId = Long.valueOf(opensearch.get("maxId").toString());
            if (-1L == maxId) {
                open = false;
            }
        }

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        searchSourceBuilder.query(QueryBuilders.matchQuery("ad_client_id", user.getClientId()));
        if (null != searchtypes && null != fixedcolumns) {
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            if (null != storeIds && storeIds.size() > 0) {
                if (storeIds.size() > 1000) {
                    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                    int pagesize = storeIds.size() / 1000;
                    for (int i = 0; i < pagesize; i++) {
                        storeIds.add((i + 1) * 1000, "a");
                    }
                    String storebuf = storeIds.toJSONString().replace("[", "").replace("]", "");
                    String[] stos = storebuf.split("a");
                    for (int j = 0; j < stos.length; j++) {
                        String sto = stos[j];
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.append("[");
                        if (j == 0) {
                            sto = sto.substring(0, sto.length() - 1);
                        } else if (j > 0 && j < stos.length - 1) {
                            sto = sto.substring(0, sto.length() - 1);
                            sto = sto.substring(1, sto.length());
                        } else {
                            sto = sto.substring(1, sto.length());
                        }
                        stringBuilder.append(sto + "]");
                        JSONArray jor = JSONArray.parseArray(stringBuilder.toString());
                        boolQueryBuilder.should(QueryBuilders.termsQuery("acc.cp_c_store_id", jor));
                    }
                    queryBuilder.must(boolQueryBuilder);
                } else {
                    queryBuilder.must(QueryBuilders.termsQuery("acc.cp_c_store_id", storeIds));
                }
            }
            for (int i = 0; i < searchtypes.size(); i++) {
                JSONObject searchtype = searchtypes.getJSONObject(i);
                if (null != searchtype && searchtype.size() > 0) {
                    String name = searchtype.getString("name").toLowerCase();
                    String type = searchtype.getString("type");
                    String value = fixedcolumns.getString(name.toUpperCase());
                    if ("index".equals(type)) {
                        if ("acc_isactive".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.size(); j++) {
                                shoudBuilder.should(QueryBuilders.matchQuery("acc." + name, values.getString(j)));
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("complete".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.size(); j++) {
                                shoudBuilder.should(QueryBuilders.matchQuery(name, values.getString(j)));
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("ename".equals(name)) {
                            String[] values;
                            if (value.contains(",")) {
                                values = value.split(",");
                            } else {
                                values = value.split("\\s+");
                            }
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.length; j++) {
                                shoudBuilder.should(QueryBuilders.matchPhrasePrefixQuery(name, values[j]));
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("mobil".equals(name)) {
                            String[] values;
                            if (value.contains(",")) {
                                values = value.split(",");
                            } else {
                                values = value.split("\\s+");
                            }
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.length; j++) {
                                shoudBuilder.should(QueryBuilders.wildcardQuery(name, "*" + values[j] + "*"));
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("vp_c_viptypegroup_id".equals(name) || "vp_c_viptype_id".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            if (null != values && values.size() > 0) {
                                queryBuilder.must(QueryBuilders.termsQuery("acc." + name, values));
                            }
                        } else if ("vp_c_viptypegroup_id:ename".equals(name)) {
                            queryBuilder.must(QueryBuilders.matchQuery("acc.vp_c_viptypegroup_id", value));
                        } else if ("vp_c_viptype_id:ename".equals(name)) {
                            queryBuilder.must(QueryBuilders.matchQuery("acc.vp_c_viptype_id", value));
                        } else if ("ecodes".equals(name)) {
                            String[] values;
                            if (value.contains(",")) {
                                values = value.split(",");
                            } else {
                                values = value.split("\\s+");
                            }
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.length; j++) {
                                shoudBuilder.should(QueryBuilders.wildcardQuery("acc.ecodes", "*" + values[j] + "*"));
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("cp_c_store_id".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            if (null != values && values.size() > 1000) {
                                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                                int pagesize = values.size() / 1000;
                                for (int j = 0; j < pagesize; j++) {
                                    values.add((j + 1) * 1000, "a");
                                }
                                String storebuf = values.toJSONString().replace("[", "").replace("]", "");
                                String[] stos = storebuf.split("a");
                                for (int j = 0; j < stos.length; j++) {
                                    String sto = stos[j];
                                    StringBuilder stringBuilder = new StringBuilder();
                                    stringBuilder.append("[");
                                    if (j == 0) {
                                        sto = sto.substring(0, sto.length() - 1);
                                    } else if (j > 0 && j < stos.length - 1) {
                                        sto = sto.substring(0, sto.length() - 1);
                                        sto = sto.substring(1, sto.length());
                                    } else {
                                        sto = sto.substring(1, sto.length());
                                    }
                                    stringBuilder.append(sto + "]");
                                    JSONArray jor = JSONArray.parseArray(stringBuilder.toString());
                                    boolQueryBuilder.should(QueryBuilders.termsQuery("acc.cp_c_store_id", jor));
                                }
                                queryBuilder.must(boolQueryBuilder);
                            } else if (null != values && values.size() > 0) {
                                queryBuilder.must(QueryBuilders.termsQuery("acc.cp_c_store_id", values));
                            }
                        }
                    } else if ("filter".equals(type)) {
                        //DOTO
                        if ("opendate".equals(name)) {
                            String min = value.split("~")[0];
                            String max = value.split("~")[1];
                            RangeQueryBuilder minMaxBuilder = new RangeQueryBuilder("acc." + name);
                            try {
                                int minNumber = Integer.parseInt(min);
                                minMaxBuilder.gte(minNumber);
                                queryBuilder.filter(minMaxBuilder);
                            } catch (Exception e) {

                            }
                            try {
                                int maxNumber = Integer.parseInt(max);
                                minMaxBuilder.lte(maxNumber);
                                queryBuilder.filter(minMaxBuilder);
                            } catch (Exception e) {

                            }
                        } else if ("acc_inte".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            BoolQueryBuilder shoudBuilder = QueryBuilders.boolQuery();
                            for (int j = 0; j < values.size(); j++) {
                                String min = values.getString(j).split("~")[0];
                                String max = values.getString(j).split("~")[1];
                                RangeQueryBuilder minMaxBuilder = new RangeQueryBuilder("acc." + name);
                                try {
                                    int minNumber = Integer.parseInt(min);
                                    minMaxBuilder.gte(minNumber);
                                } catch (Exception e) {

                                }
                                try {
                                    int maxNumber = Integer.parseInt(max);
                                    minMaxBuilder.lte(maxNumber);

                                } catch (Exception e) {

                                }
                                shoudBuilder.should(minMaxBuilder);
                            }
                            queryBuilder.must(shoudBuilder);
                        } else if ("id".equals(name)) {
                            String min = value.split("~")[0];
                            String max = value.split("~")[1];
                            RangeQueryBuilder minMaxBuilder = new RangeQueryBuilder(name);
                            try {
                                Long minNumber = Long.parseLong(min);
                                minMaxBuilder.gte(minNumber);
                                queryBuilder.filter(minMaxBuilder);
                            } catch (Exception e) {

                            }
                            try {
                                Long maxNumber = Long.parseLong(max);
                                minMaxBuilder.lte(maxNumber);
                                queryBuilder.filter(minMaxBuilder);
                            } catch (Exception e) {

                            }
                        }
                    } else if ("exact".equals(type)) {
                        queryBuilder.must(QueryBuilders.matchQuery(name, value));
                    }
                }
                searchSourceBuilder.query(queryBuilder);
            }
        }
        //每页显示数量
        int range = 0;
        if (StringUtils.isNotEmpty(TypeUtils.castToString(param.get("range")))) {
            range = TypeUtils.castToInt(param.get("range"));
        }

        //起始数量
        int startindex = 0;
        if (StringUtils.isNotEmpty(TypeUtils.castToString(param.get("startindex")))) {
            startindex = param.getInteger("startindex");
        }
        if (range == 0) {
            searchSourceBuilder.size(100);
        } else {
            searchSourceBuilder.from(startindex).size(range);
        }

        //添加soft
        //排序:+升序 -降序
        if (null != orderby && orderby.size() > 0) {
            for (int i = 0; i < orderby.size(); i++) {
                JSONObject softJson = JSON.parseObject(TypeUtils.castToString(orderby.get(i)));
                if (null != softJson && softJson.size() > 0) {
                    Boolean order = softJson.getBooleanValue("asc");
                    String name = softJson.getString("name");
                    if (null != name && !"".equals(name) && name.indexOf(".") != -1) {
                        name = name.split("\\.")[1];
                    }
                    if (order) {
                        SortBuilder sortBuilder = SortBuilders.fieldSort(name.toLowerCase()).order(SortOrder.ASC);
                        searchSourceBuilder.sort(sortBuilder);
                    } else if (!order) {
                        SortBuilder sortBuilder = SortBuilders.fieldSort(name.toLowerCase()).order(SortOrder.DESC);
                        searchSourceBuilder.sort(sortBuilder);
                    }
                }
            }
        } else {
            SortBuilder sortBuilder = SortBuilders.fieldSort("id").order(SortOrder.DESC);
            searchSourceBuilder.sort(sortBuilder);
        }

        String[] fields = {"id"};
        FetchSourceContext sourceContext = new FetchSourceContext(fields);
        searchSourceBuilder.fetchSource(sourceContext);

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(pconf.getProperty("vip_opensearch_index"))
                .addType(pconf.getProperty("vip_opensearch_index"))
                .build();
        try {
            SearchResult result = jestClient.execute(search);
            if (result.isSucceeded()) {
                JsonArray jsonArray = result.getJsonObject().getAsJsonObject("hits").getAsJsonArray("hits");
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("IN (");
                JSONArray ids = new JSONArray();
                if (null != jsonArray && jsonArray.size() > 0) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JsonObject jsonObject = jsonArray.get(i).getAsJsonObject().getAsJsonObject("_source");
                        Long id = jsonObject.get("id").getAsLong();
                        ids.add(id);
                        if (i == jsonArray.size() - 1) {
                            stringBuilder.append(id);
                        } else {
                            stringBuilder.append(id).append(",");
                        }
                    }
                    valueHolder.put("ROWCOUNT", jsonArray.size());
                } else {
                    valueHolder.put("ROWCOUNT", 0);
                    stringBuilder.append(0);
                }
                stringBuilder.append(")");
                if (null != param.getString("issql") && param.getBoolean("issql")) {
                    valueHolder.put("IDS", stringBuilder);
                } else {
                    valueHolder.put("IDS", ids);
                }
                valueHolder.put("code", 0);
                valueHolder.put("TOTAL", result.getTotal());
            } else {
                valueHolder.put("code", -1);
                if (null != param.getString("issql") && param.getBoolean("issql")) {
                    String ids = "(0)";
                    valueHolder.put("IDS", ids);
                } else {
                    JsonArray ids = new JsonArray();
                    valueHolder.put("IDS", ids);
                }
                valueHolder.put("TOTAL", 0);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Double spendTime = runtimeCompute.endRuntime();
//        log.debug("vip_spentime-->" + spendTime);
        return valueHolder;
    }

    private ValueHolder opensearch(QuerySession querySession, Long maxId, JSONArray ids) {
        ValueHolder valueHolder = new ValueHolder();
        DefaultWebEvent event = querySession.getEvent();
        JSONObject param = JSON.parseObject(JSON.toJSONStringWithDateFormat(event.getParameterValue("param"), "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteMapNullValue), Feature.OrderedField);
        String accesskey = pconf.getProperty("ons.accessKey");
        String secret = pconf.getProperty("ons.secretKey");
        String host = "http://opensearch-cn-hangzhou.aliyuncs.com/";
        String appName = pconf.getProperty("cp_c_store_bucket");
        OpenSearch openSearch = new OpenSearch(accesskey, secret, host);
        OpenSearchClient serviceClient = new OpenSearchClient(openSearch);
        SearcherClient searcherClient = new SearcherClient(serviceClient);
        Config config = new Config(Lists.newArrayList(appName));
        //设置返回格式为fulljson格式
        config.setSearchFormat(SearchFormat.JSON);

        // 创建参数对象
        SearchParams searchParams = new SearchParams(config);

        JSONArray indexArray = new JSONArray();
        JSONArray filterArray = new JSONArray();
        //获取查询条件字段类型是index还是filter
        JSONArray searchtypes = param.getJSONArray("searchtype");
        //获取查询条件字段
        JSONObject fixedcolumns = param.getJSONObject("fixedcolumns");
        //获取排序字段
        JSONArray orderby = param.getJSONArray("orderby");
        if (null != searchtypes && null != fixedcolumns) {
            for (int i = 0; i < searchtypes.size(); i++) {
                JSONObject searchtype = searchtypes.getJSONObject(i);
                if (null != searchtype && searchtype.size() > 0) {
                    String name = searchtype.getString("name").toLowerCase();
                    String type = searchtype.getString("type");
                    String value = fixedcolumns.getString(name.toUpperCase());
                    if ("index".equals(type)) {
                        StringBuilder index = new StringBuilder();
                        if ("cp_c_distrib_id:ename".equals(name)) {
                            String[] values = value.split(",");
                            for (int j = 0; j < values.length; j++) {
                                if (values.length > 1) {
                                    if (j == 0) {
                                        index.append("(cp_c_distrib_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (0 < j && j < values.length - 1) {
                                        index.append(" OR cp_c_distrib_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (j == values.length - 1) {
                                        index.append(" OR cp_c_distrib_id_ename").append(":'").append(values[j]).append("')");
                                    }
                                } else if (values.length == 1) {
                                    index.append("cp_c_distrib_id_ename").append(":'").append(values[j]).append("'");
                                }
                            }
                            indexArray.add(index);
                        } else if ("cp_c_distrib_id".equals(name) || "cp_c_storeorg_id".equals(name)) {
                            JSONArray values = JSON.parseArray(value);
                            if (null != values && values.size() > 0) {
                                index.append(name).append(":'").append(values.get(0)).append("'");
                            }
                            indexArray.add(index);
                        } else if ("cp_c_storeorg_id:ename".equals(name)) {
                            String[] values = value.split(",");
                            for (int j = 0; j < values.length; j++) {
                                if (values.length > 1) {
                                    if (j == 0) {
                                        index.append("(cp_c_storeorg_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (0 < j && j < values.length - 1) {
                                        index.append(" OR cp_c_storeorg_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (j == values.length - 1) {
                                        index.append(" OR cp_c_storeorg_id_ename").append(":'").append(values[j]).append("')");
                                    }
                                } else if (values.length == 1) {
                                    index.append("cp_c_storeorg_id_ename").append(":'").append(values[j]).append("'");
                                }
                            }
                            indexArray.add(index);
                        } else if ("cp_c_store_id:ename".equals(name)) {
                            String[] values = value.split(",");
                            for (int j = 0; j < values.length; j++) {
                                if (values.length > 1) {
                                    if (j == 0) {
                                        index.append("(cp_c_store_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (0 < j && j < values.length - 1) {
                                        index.append(" OR cp_c_store_id_ename").append(":'").append(values[j]).append("'");
                                    } else if (j == values.length - 1) {
                                        index.append(" OR cp_c_store_id_ename").append(":'").append(values[j]).append("')");
                                    }
                                } else if (values.length == 1) {
                                    index.append("cp_c_store_id_ename").append(":'").append(values[j]).append("'");
                                }
                            }
                            indexArray.add(index);
                        }
                    } else if ("filter".equals(type)) {
//                        StringBuilder filter = new StringBuilder();
//                        filter.append(name).append("=").append(value);
                    }
                }
            }
        }

        StringBuilder indexBuilder = new StringBuilder();
//        indexBuilder.append("ad_client_id:'" + user.getClientId() + "'");
        //添加索引
        if (null != indexArray && indexArray.size() > 0) {
            for (int i = 0; i < indexArray.size(); i++) {
                if (i == 0) {
                    indexBuilder.append(TypeUtils.castToString(indexArray.get(i)));
                } else {
                    indexBuilder.append(" AND ").append(TypeUtils.castToString(indexArray.get(i)));
                }

            }
        } else {
            valueHolder.put("code", "0");
            valueHolder.put("maxId", -1L);
            return valueHolder;
        }
        if (indexBuilder != null) {
            searchParams.setQuery(indexBuilder.toString());
        }
        StringBuilder filterBuilder = new StringBuilder();
        filterBuilder.append("id").append(">").append(maxId);
        searchParams.setFilter(TypeUtils.castToString(filterBuilder));

        config.setStart(0);
        config.setHits(500);
        Sort sort = new Sort();
        sort.addToSortFields(new SortField(("id"), Order.INCREASE));
        searchParams.setSort(sort);
        //执行查询语句返回数据对象
        com.aliyun.opensearch.sdk.generated.search.general.SearchResult searchResult = null;
        try {
            searchResult = searcherClient.execute(searchParams);
        } catch (OpenSearchException e) {
            e.printStackTrace();
        } catch (OpenSearchClientException e) {
            e.printStackTrace();
        }
        JSONObject searchJson = JSON.parseObject(searchResult.getResult());
        JSONObject resultJson = searchJson.getJSONObject("result");
        int total = resultJson.getInteger("total");
        JSONArray items = resultJson.getJSONArray("items");
        maxId = -1L;
        if (null != items && items.size() > 0) {
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = items.getJSONObject(i);
                Long id = item.getLong("id");
                ids.add(id);
                if (i == 499 && total > 500) {
                    maxId = id;
                }
            }
        } else {
            ids.add(-1);
        }
        if ("FAIL".equals(searchJson.getString("status"))) {
            valueHolder.put("code", "-1");
            JSONArray errors = searchJson.getJSONArray("errors");
            String message = null;
            if (null != errors && null != errors.getJSONObject(0)) {
                message = errors.getJSONObject(0).getString("message");
            }
            valueHolder.put("message", message);
        } else {
            valueHolder.put("code", "0");
//            valueHolder.put("storeids", ids);
            valueHolder.put("maxId", maxId);
        }
        return valueHolder;
    }
}
